import tkinter as tk
import tkinter.messagebox
import socket
import winsound
import os
import pickle
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
d={}#name:ip
vd={}#ip:name
mslist=[]
#start-ip

our_name=""
#start-ip
def loading():
    global our_name,d,mslist,vd
    try:
        with open("chater.cfg",mode="rb") as f:
            listemp=pickle.load(f)
            if not type(listemp)==list and len(listemp)==3:
                return False
            if listemp[0]=="": return False
            our_name=listemp[0]
            d=listemp[1]
            vd={v: k for k, v in d.items()}
            mslist=listemp[2]
        return True
    except:
        return False


def dumping(flag=True):
    if not flag:
        with open("chater.cfg",mode="wb") as f:
            pickle.dump([our_name,d,tuple()],f)
        return
    with open("chater.cfg",mode="wb") as f:
        pickle.dump([our_name,d,listm.get(0,"end")],f)


def is_valid_ipv4_address(ip_str):
    sep = ip_str.split('.')
    if len(sep) != 4:
        return False
    for i,x in enumerate(sep):
        try:
            int_x = int(x)
            if int_x < 0 or int_x > 255:
                return False
        except ValueError as e:
            return False
    return True

def binding(ip):
    if is_valid_ipv4_address(ip):
        s.bind((ip,8080))
        s.setblocking(0)
        
if not loading():
    def getsip():
        global our_name,d,vd
        our_name=e.get()
        if is_valid_ipv4_address(our_name):
            try:
                binding(our_name)
                d={"全局广播":".".join(our_name.split(".")[:-1])+".255"}
                vd={v: k for k, v in d.items()}

            except:
                tkinter.messagebox.showerror("错误","这不是你的IP地址！")
            else:
                dumping(False)
                nroot.destroy()
        else:
            tkinter.messagebox.showerror("错误","IP格式错误！")
    nroot=tk.Tk()
    nroot.title("")
    name=""
    tk.Label(nroot,text="本机IP地址:").grid(row=0,column=0,rowspan=1,columnspan=3)
    e=tk.Entry(nroot)
    e.grid(row=1,column=0,rowspan=1,columnspan=2)
    b=tk.Button(nroot,text="确定",command=getsip)
    b.grid(row=1,column=2,rowspan=1,columnspan=1)
    nroot.mainloop()
else:
    binding(our_name)



wtest=lambda x:"TTL" in os.popen("ping /n 1 "+x).read()
def fr():
    def nd():
        global vd
        name=e1.get()
        cname=e2.get()
        if is_valid_ipv4_address(name):
            if not wtest(name):
                tkinter.messagebox.showwarning("警告","IP未连通，对方可能不在线！")
            listb.insert("end",cname)
            d[cname]=name
            vd={v: k for k, v in d.items()}
            dumping()
            nroot.destroy()
        else:
            tkinter.messagebox.showerror("错误","IP格式错误！")
    nroot=tk.Tk()
    nroot.title("")
    name=""
    
    tk.Label(nroot,text="IP地址:").grid(row=0,column=0,rowspan=1,columnspan=3)
    e1=tk.Entry(nroot)
    e1.grid(row=1,column=0,rowspan=1,columnspan=3)
    
    tk.Label(nroot,text="计算机名（自定义）:").grid(row=2,column=0,rowspan=1,columnspan=3)
    e2=tk.Entry(nroot)
    e2.grid(row=3,column=0,rowspan=1,columnspan=3)
    
    b=tk.Button(nroot,text="确定",command=nd)
    b.grid(row=4,column=0,rowspan=1,columnspan=3)
    nroot.mainloop()
def reload():
    try:
        while True:
            data, addr = s.recvfrom(65536)
            winsound.Beep(1000,500)
            if addr[0] in vd: listm.insert("end", vd[addr[0]] + ":" + data.decode("utf-8"))
            else: listm.insert("end", addr[0] + ":" + data.decode("utf-8"))
            dumping()
    except:
        pass
    finally:
        root.after(250, reload)

        
def sent():
    text=e.get()
    try:
        addr=d[listb.get(listb.curselection())]
        e.delete("0","end")
    except:
        tkinter.messagebox.showerror("错误","您似乎没选收件人...")
    else:
        s.sendto(text.encode("utf-8"),(addr,8080))
        listm.insert("end","我=>"+vd[addr]+":"+text)
        dumping()
def dell():
    del d[listb.get("active")]
    vd={v: k for k, v in d.items()}
    listb.delete("active")
    dumping()
root=tk.Tk()
root.title("Hello Foolish-man聊天器")
listb=tk.Listbox(root,selectmode=tk.SINGLE)
listb.grid(row=0,column=0,rowspan=5,columnspan=2)

buttonins=tk.Button(root,text="添加联系人",command=fr)
buttondel=tk.Button(root,text="删除联系人",command=dell)
# 移动按钮到第6行，避免与listb重叠
buttonins.grid(row=6,column=0)
buttondel.grid(row=6,column=1)

listm=tk.Listbox(root,width=40)
listm.grid(row=0,column=2,rowspan=6,columnspan=5)

e=tk.Entry(root)
# 移动e到listm不占据的列上，例如第7列
e.grid(row=6,column=2,rowspan=1,columnspan=4)
buttonsnd=tk.Button(root,text="发送",command=sent)
buttonsnd.grid(row=6,column=6)
for k in d:
    listb.insert("end",k)
for i in mslist:
    listm.insert("end",i)
reload()
root.mainloop()


